import { Vec2, Segment, Path } from "./geometry";
import { ActiveEdge } from "./ael";
import Color from "colorjs.io";
import { Mathf } from "./mathf";

export interface DrawPathOption {
  strokeColor: string;
  fillColor?: string;
  close?: boolean;
  arrow?: boolean;
}

export class WorkCanvas {
  canvas: HTMLCanvasElement;
  context: CanvasRenderingContext2D;

  get width() {
    return this.canvas.width;
  }

  get height() {
    return this.canvas.height;
  }

  constructor(id: string) {
    this.canvas = document.getElementById(id) as HTMLCanvasElement;
    this.context = this.canvas.getContext("2d")!;
  }

  drawPoint(p: Vec2, color: string = "blue", w: number = 4) {
    this.context.fillStyle = color;
    this.context.beginPath();
    this.context.fillRect(p.x - w / 2, p.y - w / 2, w, w);
  }

  drawPoints(ps: Vec2[], color: string = "blue", w: number = 4) {
    for (const p of ps) {
      this.drawPoint(p, color, w);
    }
  }

  drawSegment(segment: Segment, color: string = "grey") {
    this.context.strokeStyle = color;
    this.context.beginPath();
    this.context.moveTo(segment.p1.x, segment.p1.y);
    this.context.lineTo(segment.p2.x, segment.p2.y);
    this.context.stroke();
  }

  drawSegments(segments: Segment[], color: string = "grey") {
    this.context.strokeStyle = color;
    this.context.beginPath();
    for (const segment of segments) {
      this.context.moveTo(segment.p1.x, segment.p1.y);
      this.context.lineTo(segment.p2.x, segment.p2.y);
    }
    this.context.stroke();
  }

  drawPath(path: Path, option: DrawPathOption) {
    if (option.fillColor) {
      this.initFillColor(option.fillColor);
    } else {
      this.context.strokeStyle = option.strokeColor;
    }

    this.context.beginPath();
    this.context.moveTo(path.points[0].x, path.points[0].y);
    for (let i = 1; i < path.points.length; i++) {
      this.context.lineTo(path.points[i].x, path.points[i].y);
    }
    if (option.close) {
      this.context.closePath();
    }

    if (option.fillColor) {
      this.context.fill();
    } else {
      this.context.stroke();
    }

    for (let i = 0; i < path.points.length - 1; i++) {
      this.drawArrow(path.points[i], path.points[i + 1]);
    }
    if (option.close) {
      this.drawArrow(path.points[path.points.length - 1], path.points[0]);
    }

    this.drawText(
      path.points[0].add(new Vec2(-30, 10)),
      "v0",
      option.strokeColor,
      20
    );
  }

  drawPaths(paths: Path[], option: DrawPathOption) {
    for (const path of paths) {
      this.drawPath(path, option);
    }
  }

  initFillColor(color: string) {
    let strokeColor = new Color(color);
    strokeColor.darken(0.2);
    this.context.strokeStyle = strokeColor.toString();
    this.context.fillStyle = color;
  }

  randomColor() {
    let r = Math.random();
    let g = Math.random();
    let b = Math.random();
    let a = Math.random();
    //   a = Math.min(Math.max(0.4, a), 0.6);
    let color = new Color("srgb", [r, g, b], 0.5);
    return color.toString();
  }

  drawScanLine(y: number) {
    this.context.setLineDash([3, 2]);
    this.context.strokeStyle = "grey";
    this.context.beginPath();
    this.context.moveTo(0, y);
    this.context.lineTo(bgCanvas.width, y);
    this.context.stroke();
  }

  clear() {
    this.context.clearRect(0, 0, this.width, this.height);
  }

  drawText(p: Vec2, text: string, color = "blue", fontSize = 20) {
    this.context.font = `${fontSize}px Verdana`;
    this.context.fillStyle = color;
    this.context.fillText(text, p.x, p.y);
  }

  labelOnEdge(edge: ActiveEdge, y: number, text: string, fontSize = 20) {
    let t = (y - edge.bottom.y) / (edge.top.y - edge.bottom.y);
    let p = Vec2.lerp(t, edge.bottom.point, edge.top.point);

    this.context.font = `${fontSize}px Verdana`;
    this.context.fillStyle = edge.localMin.properties;
    this.context.fillText(text, p.x, p.y);
  }

  drawArrow(p1: Vec2, p2: Vec2) {
    let midp = p1.add(p2).div(2);
    let v = p1.sub(p2).normalize();
    let n = new Vec2(-v.y, v.x);
    let deg = Mathf.deg2Rad(15);
    let x = Math.cos(deg);
    let y = Math.sin(deg);
    let pa = v.mul(x).add(n.mul(y)).mul(10).add(midp);
    let pb = v.mul(x).add(n.mul(-y)).mul(10).add(midp);
    this.context.beginPath();
    this.context.moveTo(pa.x, pa.y);
    this.context.lineTo(midp.x, midp.y);
    this.context.lineTo(pb.x, pb.y);
    this.context.stroke();
  }
}

export let bgCanvas = new WorkCanvas("background-canvas");
export let fgCanvas = new WorkCanvas("forground-canvas");
